package main

import (
	"errors"
	"fmt"
	"log"
	"net"
	"strconv"
	"strings"

	"gitee.com/hailaz/wakeonlan/arp"
	_ "gitee.com/hailaz/wakeonlan/routers"
	"github.com/astaxie/beego"
	_ "github.com/icattlecoder/godaemon"
)

func main() {
	//fmt.Println(GetOutboundIP())

	//fmt.Println(ExternalIP())
	// Get a list of all interfaces.

	beego.Run()
}

// Get preferred outbound ip of this machine
func GetOutboundIP() net.IP {
	conn, err := net.Dial("udp", "114.114.114.114:80")
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	localAddr := conn.LocalAddr().(*net.UDPAddr)
	return localAddr.IP
}

func ExternalIP() (string, string, error) {
	ifaces, err := net.Interfaces()
	if err != nil {
		return "", "", err
	}
	for _, iface := range ifaces {
		if iface.Flags&net.FlagUp == 0 {
			continue // interface down
		}
		if iface.Flags&net.FlagLoopback != 0 {
			continue // loopback interface
		}
		addrs, err := iface.Addrs()
		if err != nil {
			return "", "", err
		}
		for _, addr := range addrs {
			var ip net.IP
			var ipnet *net.IPNet
			switch v := addr.(type) {
			case *net.IPNet:
				ipnet = v
			case *net.IPAddr:
			}
			ip = ipnet.IP
			if ip == nil || ip.IsLoopback() {
				continue
			}
			ip = ip.To4()
			if ip == nil {
				continue // not an ipv4 address
			}

			if !ip.Equal(GetOutboundIP()) {
				continue
			}
			baseIP := ip.Mask(ipnet.Mask)
			min := IPToUInt32(baseIP)
			max := (^uint32(0)) >> 20
			for item, _ := range arp.Table() {
				tempIP := net.ParseIP(item)
				if tempIP.Mask(ipnet.Mask).Equal(baseIP) {
					if !UInt32ToIP(min + uint32(max)).Equal(tempIP) {
						fmt.Printf("%s : %s\n", item, arp.Search(item))
					}
				}
			}
			//fmt.Println(ip.String(), iface.HardwareAddr.String())
			return ip.String(), iface.HardwareAddr.String(), nil
		}
	}
	return "", "", errors.New("are you connected to the network?")
}

func IPToUInt32(ipnr net.IP) uint32 {
	bits := strings.Split(ipnr.String(), ".")
	b0, _ := strconv.Atoi(bits[0])
	b1, _ := strconv.Atoi(bits[1])
	b2, _ := strconv.Atoi(bits[2])
	b3, _ := strconv.Atoi(bits[3])

	var sum uint32

	sum += uint32(b0) << 24
	sum += uint32(b1) << 16
	sum += uint32(b2) << 8
	sum += uint32(b3)

	return sum
}

func UInt32ToIP(intIP uint32) net.IP {
	var bytes [4]byte
	bytes[0] = byte(intIP & 0xFF)
	bytes[1] = byte((intIP >> 8) & 0xFF)
	bytes[2] = byte((intIP >> 16) & 0xFF)
	bytes[3] = byte((intIP >> 24) & 0xFF)

	return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])
}
